//
//  NSObject+Safe.m
//  niuguwang
//
//  Created by BrightLi on 2021/6/5.
//  Copyright © 2021年 taojinzhe. All rights reserved.
//

#import "NSObject+Safe.h"
#import "YMSafeUtil.h"
#import <objc/runtime.h>

@interface _UnregSelObjectProxy : NSObject

+ (instancetype) sharedInstance;

@end

@implementation _UnregSelObjectProxy

+ (instancetype) sharedInstance{
    
    static _UnregSelObjectProxy *instance=nil;
    static dispatch_once_t once_token;
    dispatch_once(&once_token, ^{
        instance = [[_UnregSelObjectProxy alloc] init];
    });
    return instance;
}

+ (BOOL) resolveInstanceMethod:(SEL)selector
{
    class_addMethod([self class], selector,(IMP)emptyMethodIMP,"v@:");
    return YES;
}

void emptyMethodIMP()
{
    NSLog(@"emptyMethodIMP");
}

@end

static const void *keypathMapKey=&keypathMapKey;
static const void *kvoSafeToggleKey=&kvoSafeToggleKey;

@implementation NSObject(Safe)

+ (void) safe_fixed
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        [YMSafeUtil swizzleInstance:[self class]
                          sel1:@selector(setValue:forKey:)
                          sel2:@selector(safe_setValue:forKey:)];
        [YMSafeUtil swizzleInstance:[self class]
                          sel1:@selector(setValue:forKeyPath:)
                          sel2:@selector(safe_setValue:forKeyPath:)];
        [YMSafeUtil swizzleInstance:[self class]
                          sel1:@selector(setValue:forUndefinedKey:)
                          sel2:@selector(safe_setValue:forUndefinedKey:)];
        [YMSafeUtil swizzleInstance:[self class]
                          sel1:@selector(setValuesForKeysWithDictionary:)
                          sel2:@selector(safe_setValuesForKeysWithDictionary:)];
        [YMSafeUtil swizzleInstance:[self class]
                  sel1:@selector(addObserver:forKeyPath:options:context:)
                  sel2:@selector(safe_addObserver:forKeyPath:options:context:)];
        [YMSafeUtil swizzleInstance:[self class]
                  sel1:@selector(removeObserver:forKeyPath:)
                  sel2:@selector(safe_removeObserver:forKeyPath:)];
        if (@available(iOS 14.0, *)) {
        
        }else{
            [YMSafeUtil swizzleInstance:[self class]
            sel1:@selector(methodSignatureForSelector:)
            sel2:@selector(safe_methodSignatureForSelector:)];
        }
        [YMSafeUtil swizzleInstance:[self class]
                  sel1:@selector(forwardInvocation:)
                  sel2:@selector(safe_forwardInvocation:)];
    });
}
         
-(void) safe_setValue:(id)value forKey:(NSString *)key
{
    @try{
        [self safe_setValue:value forKey:key];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

- (void) safe_setValue:(id)value forKeyPath:(NSString *)keyPath
{
    @try{
        [self safe_setValue:value forKeyPath:keyPath];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

- (void) safe_setValue:(id)value forUndefinedKey:(NSString *)key
{
    @try{
        [self safe_setValue:value forUndefinedKey:key];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

- (void) safe_setValuesForKeysWithDictionary:(NSDictionary<NSString *,id> *)keyedValues
{
    @try{
        [self safe_setValuesForKeysWithDictionary:keyedValues];
    }
    @catch (NSException *exception) {
        [YMSafeUtil stackLog:exception start:5];
    }
    @finally {
    }
}

-(void) safe_addObserver:(NSObject *)observer
           forKeyPath:(NSString *)keyPath
              options:(NSKeyValueObservingOptions)options
              context:(void *)context
{
    [self safe_addObserver:observer forKeyPath:keyPath options:options context:context];
}

-(void) safe_removeObserver:(NSObject *)observer
              forKeyPath:(NSString *)keyPath
{
    @try{
        [self safe_removeObserver:observer forKeyPath:keyPath];
    }
    @catch (NSException *exception) {
        NSLog(@"删除KVO失败:%@",keyPath);
    }
}
// 是否已有KVO
- (BOOL)hasKey:(NSString *)kvoKey {
    if(kvoKey.length<1){
        return false;
    }
    BOOL hasKey = NO;
    id info = self.observationInfo;
    NSArray *list = [info valueForKeyPath:@"_observances._property._keyPath"];
    for (id keypath in list) {
        // 存在kvo 的key
        if ([keypath isEqualToString:kvoKey]) {
            hasKey = YES;
            break;
        }
    }
    return hasKey;
}

- (void) safe_originalDealloc{
    NSLog(@"?");
}

- (NSMethodSignature *)safe_methodSignatureForSelector:(SEL)sel
{
    NSMethodSignature *sig;
    sig = [self safe_methodSignatureForSelector:sel];
    if (sig) {
        return sig;
    }
    NSString *className=NSStringFromClass([self class]);
    NSString *selName=[[NSString alloc] initWithUTF8String:sel_getName(sel)];
    if([className hasPrefix:@"UIKeyboardInputManager"] || [className hasPrefix:@"_"]){
        return nil;
    }
    [YMSafeUtil log:@"%@-%@",className,selName];
    sig = [[_UnregSelObjectProxy sharedInstance] safe_methodSignatureForSelector:sel];
    if (sig){
        return sig;
    }
    return nil;
}

-(void) safe_forwardInvocation:(NSInvocation *)anInvocation
{
    [anInvocation invokeWithTarget:[_UnregSelObjectProxy sharedInstance]];
    NSString *cls=NSStringFromClass([self class]);
    NSString *method=NSStringFromSelector(anInvocation.selector);
    [YMSafeUtil log:@"找不到实现方法:[%@ %@]",cls,method];
}

@end
